import { MangaSite } from "../MangaSite";
import {joinPath, writeFile} from "../../../function/fileFunc";
import {requestText} from "../../../function/httpFunc";
import {parseXML, reduceHTML2SimpleXML, StXML} from "../../../function/xmlFunc";
import { enc, AES, mode, pad } from "crypto-js";
declare const chapterImages: string;
declare const chapterPath: string;
export namespace ManHuaDui {
    export interface ImgItemInfo extends  MangaSite.ImgItemInfo {
    }
    export interface TravelBaseNode extends StXML.BaseNode {
        traveled: boolean;
        children: TravelNode[];
    }
    export interface TravelTextNode extends StXML.TextNode {
        traveled: boolean;
    }
    export type TravelNode = TravelBaseNode | TravelTextNode;
}

export class ManHuaDui extends MangaSite {
    private chapterPath: string = "";
    private chapterImgList: string[] = [];
    private encodedImgList: string;
    private comicId: string;
    private chapterId: string;
    private readonly varChapterImgStr = "chapterImages =";
    private readonly funcDecodeStr = ";decrypt20180904(";
    private readonly imgLinkPrefix = "https://img01.eshanyao.com/";
    public drawPage(img: HTMLImageElement, position?: "left" | "right", showPageIndexLen?: number): this {
        return this.directDrawPage(img, position);
    }
    public async getImgList(): Promise<MangaSite.ImgItemInfo[]> {
        console.log("get img list");
        const data = await this.getJSON();
        return JSON.parse(data) as ManHuaDui.ImgItemInfo[];
    }
    protected async cacheArticleInfoJSONFile(filename: string): Promise<string> {
        const info = this.articleInfo;
        await this.buildListReferNet(info);
        const imgList: ManHuaDui.ImgItemInfo[] = this.chapterImgList.map((imgUrl: string, imgIndex: number) => {
            return {
                imgIndex: imgIndex + 1,
                type: "ManHuaDui",
                src: imgUrl,
            };
        });
        const data = JSON.stringify(imgList);
        writeFile(filename, data);
        return Promise.resolve(data);
    }
    protected async buildListReferNet(articleInfo: MangaSite.IArticleBaseInfo) {
        console.log("build list refer net");
        const html = await requestText(articleInfo.origin_url);
        const xml = reduceHTML2SimpleXML(html);
        const node = parseXML(xml);
        const scriptList = this.getScriptListInfoFromHTML(node);
        const mainScript = scriptList.find((scriptText) => {
            return scriptText.indexOf(this.varChapterImgStr) >= 1;
        });
        this.runMainScript(mainScript);
        const decodeScript = scriptList.find((scriptText) => {
            return scriptText.indexOf(this.funcDecodeStr) >= 0;
        });
        this.runDecodeScript(decodeScript);
    }
    protected runDecodeScript(runDecodeScript: string) {
        const strIndex = runDecodeScript.indexOf(this.funcDecodeStr);
        const text = runDecodeScript.slice(strIndex + this.funcDecodeStr.length - 1);
        const matchResult = text.match(/^\((\w+),\s*["']([^"']+)["'],\s*(\w+),\s*["']([^"']+)["']\)/);
        if (matchResult) {
            this.chapterId = matchResult[1];
            const chapterName = matchResult[2];
            this.comicId = matchResult[3];
            const comicName = matchResult[4];
            this.decodeImgList(this.chapterId, chapterName, this.comicId, comicName);
        } else {
            console.error(`错误的解析方法, ${this.funcDecodeStr}`);
        }
    }
    protected decodeImgList(chapterId: string, chapterName: string, comicId: string, comicName: string) {
        const key = enc.Utf8.parse("123456781234567G");  // 十六位字符作为密钥
        // noinspection SpellCheckingInspection
        const iv = enc.Utf8.parse("ABCDEF1G34123412");
        const decrypt = AES.decrypt(chapterImages, key, {
            iv,
            mode: mode.CBC,
            padding: pad.Pkcs7,
        });
        const decryptedStr = decrypt.toString(enc.Utf8);
        const chapterImgList = JSON.parse(decryptedStr.toString());
        this.chapterImgList = chapterImgList.map((imgItem: string) => {
            return this.imgLinkPrefix + joinPath(this.chapterPath, imgItem).replace(/^[\\\/]+/, "");
        });
    }
    protected runMainScript(mainScript: string) {
        // tslint:disable-next-line:no-eval
        window.eval(mainScript);
        this.chapterPath = chapterPath;
        this.encodedImgList = chapterImages;
    }
    protected getScriptListInfoFromHTML(rootNode: StXML.BaseNode) {
        let nowNode: ManHuaDui.TravelNode = rootNode as ManHuaDui.TravelBaseNode;
        console.log(rootNode);
        const scriptTextList: string[] = [];
        nowNode.traveled = true;
        while (true) {
            if (nowNode.isText) {
                const textNode = nowNode as ManHuaDui.TravelTextNode;
                textNode.traveled = true;
                nowNode = textNode.parent as ManHuaDui.TravelBaseNode;
            } else {
                const baseNode = nowNode as ManHuaDui.TravelBaseNode;
                baseNode.traveled = true;
                if (baseNode.tagName.toLowerCase() === "script") {
                    scriptTextList.push(baseNode.children.map((scriptNode: ManHuaDui.TravelNode) => {
                        const textScriptNode = scriptNode as ManHuaDui.TravelTextNode;
                        return textScriptNode.text;
                    }).join("\n"));
                }
                nowNode = baseNode.children.find((childNode) => !childNode.traveled) as ManHuaDui.TravelNode;
                if (nowNode == null) {
                    if (baseNode.parent == null) {
                        break;
                    }
                    nowNode = baseNode.parent as ManHuaDui.TravelNode;
                }
            }
        }
        return scriptTextList.filter((scriptText) => {
            return !!(scriptText && scriptText.trim());
        });
    }
}
